/*
 * Licensed to the Tai Ping Jin Ke
 *
 * Copyright (c) 2022 .
 * All rights reserved.
 * 项目名称：太平金科-基础组件封装层-SpringBoot组件封装-缺省实现
 * 版权说明：本软件属太平金融科技服务(上海)有限公司所有，在未获得太平金融科技服务(上海)有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.taipingframework.boot.web.autoconfigure;

import ch.qos.logback.classic.helpers.MDCInsertingServletFilter;
import com.taipingframework.boot.web.advice.HttpAspect;
import com.taipingframework.boot.web.exception.handler.ApplicationExceptionHandler;
// import com.taipingframework.boot.web.interceptors.AuthorizeInterceptor;
import com.taipingframework.boot.web.filters.DefaultFilter;
import com.taipingframework.boot.web.filters.DefaultSpringFilter;
import com.taipingframework.boot.web.interceptors.DefaultInterceptor;
import com.taipingframework.boot.web.interceptors.ServiceLogThreadPoolInterceptor;
import com.taipingframework.boot.web.listeners.DefaultListener;
import com.taipingframework.boot.web.servlets.DefaultServlet;
import com.taipingframework.boot.web.servlets.MvcPathController;
import com.taipingframework.monitor.task.MonitorTask;
import com.taipingframework.utility.web.properties.MvcFilterProperty;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.Servlet;
import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})

@ComponentScan(basePackages = {"com.taipingframework.boot.web.interceptors",
        "com.taipingframework.boot.web.exception.error"}) // 此处扫描配置 Servlet服务 默认空白页处理程序
@Import(ApplicationExceptionHandler.class)
@RequiredArgsConstructor
public class SpringWebMvcAutoConfiguration implements WebMvcConfigurer {

    private final DefaultInterceptor defaultInterceptor;
    private final ServiceLogThreadPoolInterceptor serviceLogInterceptor;
    // private final AuthorizeInterceptor authorizeInterceptor;

    /**
     * 工程启动时，注册默认的Interceptor拦截器。注意：拦截器的执行顺序与只添加顺序有关系。
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(serviceLogInterceptor).addPathPatterns("/**");
        registry.addInterceptor(defaultInterceptor).addPathPatterns("/**");
        //if (authorizeInterceptor.hasAvailable()) {
        //    registry.addInterceptor(authorizeInterceptor).addPathPatterns("/**");
        //}
    }

    /**
     * 注册自定义的Servlet
     */
    @Bean
    public ServletRegistrationBean<DefaultServlet> defaultServlet(@Qualifier("asyncExecutor") ExecutorService asyncExecutor) {
        ServletRegistrationBean<DefaultServlet> defaultServlet = new ServletRegistrationBean<>();
        defaultServlet.setServlet(new DefaultServlet(asyncExecutor)); // 设置servlet对象
        defaultServlet.setUrlMappings(Collections.singleton("/default/*")); // 设置Servlet映射路径
        defaultServlet.setName("defaultServlet"); // 设置servlet名称
        defaultServlet.setAsyncSupported(true); // 配置自定义servlet支持HTTP异步请求

        defaultServlet.addInitParameter("timeout", "5000"); //设置初始化参数
        defaultServlet.setLoadOnStartup(1); // 设置启动顺序

        return defaultServlet;
    }

    /**
     * 注册自定义的Filter
     */
    @Bean
    @ConditionalOnProperty(prefix = "application.mvc.filter", name = {"enable-default-filter"}, havingValue = "true", matchIfMissing = true)
    public FilterRegistrationBean<DefaultFilter> defaultFilter(MvcFilterProperty mvcFilterProperty) {
        FilterRegistrationBean<DefaultFilter> defaultFilter = new FilterRegistrationBean<>();
        defaultFilter.setFilter(new DefaultFilter()); // 设置过滤器对象
        defaultFilter.setUrlPatterns(Collections.singleton("/*")); // 设置过滤器拦截的Servlet或者MVC处理器
        defaultFilter.setName("defaultFilter"); // 设置filter名称
        defaultFilter.setAsyncSupported(true); // 配置自定义filter支持HTTP异步请求

        defaultFilter.setInitParameters(new HashMap<String, String>() {{
            put("key1", "value1");
            put("key2", "value2");
        }});
        defaultFilter.setOrder(mvcFilterProperty.getOrderDefaultFilter()); // 设置启动顺序

        return defaultFilter;
    }

    /**
     * 注册自定义的OncePerRequestFilter
     */
    @Bean
    @ConditionalOnProperty(prefix = "application.mvc.filter", name = {"enable-spring-filter"}, havingValue = "true", matchIfMissing = true)
    public FilterRegistrationBean<DefaultSpringFilter> defaultSpringFilter(MvcFilterProperty mvcFilterProperty) {
        FilterRegistrationBean<DefaultSpringFilter> defaultSpringFilter = new FilterRegistrationBean<>();
        defaultSpringFilter.setFilter(new DefaultSpringFilter()); // 设置过滤器对象
        defaultSpringFilter.setUrlPatterns(Collections.singleton("/*")); // 设置过滤器拦截的Servlet或者MVC处理器
        defaultSpringFilter.setName("defaultSpringFilter"); // 设置filter名称
        defaultSpringFilter.setAsyncSupported(true); // 配置自定义filter支持HTTP异步请求

        defaultSpringFilter.setInitParameters(new HashMap<String, String>() {{
            put("excludeUrlPatterns", "/default");
        }});
        defaultSpringFilter.setOrder(mvcFilterProperty.getOrderSpringFilter()); // 设置启动顺序

        return defaultSpringFilter;
    }

    /**
     * 注册Slf4j内置过滤器
     */
    @Bean
    @ConditionalOnProperty(prefix = "application.mvc.filter", name = {"enable-slf4j-filter"}, havingValue = "true", matchIfMissing = true)
    public FilterRegistrationBean<MDCInsertingServletFilter> mdcInsertingServletFilter(MvcFilterProperty mvcFilterProperty) {
        FilterRegistrationBean<MDCInsertingServletFilter> mdcInsertingServletFilter = new FilterRegistrationBean<>();
        mdcInsertingServletFilter.setFilter(new MDCInsertingServletFilter()); // 设置过滤器对象
        mdcInsertingServletFilter.setUrlPatterns(Collections.singleton("/*")); // 设置过滤器拦截的Servlet或者MVC处理器
        mdcInsertingServletFilter.setName("mdcInsertingServletFilter"); // 设置filter名称
        mdcInsertingServletFilter.setAsyncSupported(true); // 配置自定义filter支持HTTP异步请求
        mdcInsertingServletFilter.setOrder(mvcFilterProperty.getOrderSlf4jFilter()); // 设置启动顺序

        return mdcInsertingServletFilter;
    }

    /**
     * 注册自定义的监听器
     */
    @Bean
    public ServletListenerRegistrationBean<DefaultListener> defaultListener(Environment environment, MonitorTask monitorTask) {
        ServletListenerRegistrationBean<DefaultListener> defaultListener = new ServletListenerRegistrationBean<>();
        defaultListener.setListener(new DefaultListener(environment, monitorTask));
        return defaultListener;
    }

    /**
     * 自定义 webmvc filter 配置参数
     */
    @Bean
    @ConfigurationProperties(prefix = "application.mvc.filter")
    public MvcFilterProperty mvcFilterProperty() {
        return new MvcFilterProperty();
    }

    /**
     * 搜集api-path列表
     */
    @Bean
    public MvcPathController mvcPathController(RequestMappingHandlerMapping requestMappingHandlerMapping) {
        return new MvcPathController(requestMappingHandlerMapping);
    }

    /**
     * aop 日志切面
     */
    @Bean
    public HttpAspect httpAspect(ServletWebServerApplicationContext applicationContext) {
        return new HttpAspect(applicationContext);
    }

    /*
     * 读写Cookie
     * 注意，此处注解@Scope的配置不适用于异步请求的应用场景
     *
    @Bean
    @Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public ServletCookieScene servletHttpCookieSerializer(
            @Autowired HttpServletRequest request,
            @Autowired HttpServletResponse response) {
        return new ServletHttpCookieSerializer(request, response);
    }

     *
     * 读写Cookie
     * 注意，ServletHttpCookieSerializer类的最新实现，
     * 不再持有HttpServletRequest 和 HttpServletResponse 的引用，
     * 实时地从当前执行线程的RequestContextHolder中获取这俩对象的副本。
     * 这个改动使得java bean`servletHttpCookieSerializer`能够同时适用于
     * 同步请求和异步请求。
     *
    @Bean
    public ServletCookieScene servletHttpCookieSerializer() {
        return new ServletHttpCookieSerializer();
    }*/

}
